package cn.ulyer.core.modules.system.service.impl;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import cn.ulyer.common.exception.BizException;
import cn.ulyer.common.jpa.entity.*;
import cn.ulyer.common.jpa.service.AbstractService;
import cn.ulyer.core.modules.system.repository.UserGroupRepository;
import cn.ulyer.core.modules.system.repository.UserRoleRespository;
import cn.ulyer.core.modules.system.service.UserService;
import com.querydsl.jpa.impl.JPAQuery;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl extends AbstractService<User,Long> implements UserService {


    @Resource
    private UserGroupRepository userGroupRepository;

    @Resource
    private UserRoleRespository userRoleRepository;

    @Override
    protected JPAQuery<?> buildPageQuery(Object queryModel) {
        User model = (User) queryModel;
        QUser qUser = QUser.user;
        JPAQuery<User> typeQuery = jpaQueryFactory.selectFrom(qUser);
        if(model!=null){
            if(StrUtil.isNotBlank(model.getUsername())){
                typeQuery.where(qUser.username.eq(model.getUsername()));
            }
            if(model.getAccountLocked()!=null){
                typeQuery.where(qUser.accountLocked.eq(model.getAccountLocked()));
            }
            if(model.getDeptId()!=null){
                typeQuery.where(qUser.deptId.eq(model.getDeptId()));
            }
            if(StrUtil.isNotBlank(model.getNickname())){
                typeQuery.where( qUser.nickname.eq(model.getNickname()));
            }
            if(StrUtil.isNotBlank(model.getPhone())){
                typeQuery.where(qUser.phone.eq(model.getPhone()));
            }
            if(model.getExpireTime()!=null){
                typeQuery.where(qUser.expireTime.gt(model.getExpireTime()));
            }
        }
        typeQuery.orderBy(qUser.createTime.desc());
        return typeQuery;
    }

    @Override
    @Transactional(rollbackOn = Throwable.class)
    public Long createUserWithGroups(User tUser, List<Integer> groups) {
        QUser qUser = QUser.user;
        long exist = jpaQueryFactory.selectFrom(qUser).where(qUser.username.eq(tUser.getUsername())).fetchCount();
        if(exist>0L){
            throw new BizException("username already exist");
        }
        Assert.notNull(tUser.getPassword(),"password must not be null");
        baseRepository.save(tUser);
        if(groups!=null){
            List<UserGroup> userGroups = new LinkedList<>();
            groups.forEach(g->{
                UserGroup ug = new UserGroup();
                ug.setUserId(tUser.getId());
                ug.setGroupId(g);
                userGroups.add(ug);
            });
            userGroupRepository.saveAll(userGroups);
        }
        return tUser.getId();
    }

    @Override
    public Map<String, Object> findRolesAndGroupsByUid(Long id) {
        Map<String,Object> data = MapUtil.newHashMap();
        QUserRole qUserRole = QUserRole.userRole;
        QUserGroup qUserGroup = QUserGroup.userGroup;
        data.put("roles",jpaQueryFactory.selectFrom(qUserRole).where(qUserRole.userId.eq(id)).fetch().stream().map(UserRole::getRoleId).collect(Collectors.toList()));
        data.put("groups",jpaQueryFactory.selectFrom(qUserGroup).where(qUserGroup.userId.eq(id)).fetch().stream().map(UserGroup::getGroupId).collect(Collectors.toList()));
        return data;
    }

    @Override
    @Transactional(rollbackOn = Throwable.class)
    public void updateGroupRoleByLoginUser(Long uid, List<Integer> roles, List<Integer> groups) {
        QUserGroup qUserGroup = QUserGroup.userGroup;
        QUserRole qUserRole = QUserRole.userRole;
        jpaQueryFactory.delete(qUserGroup).where(qUserGroup.userId.eq(uid)).execute();
        jpaQueryFactory.delete(qUserRole).where(qUserRole.userId.eq(uid)).execute();
        if(roles!=null){
            List<UserRole> userRoles = new LinkedList<>();
            roles.forEach(r->{
                UserRole ur = new UserRole();
                ur.setUserId(uid);
                ur.setRoleId(r);
                userRoles.add(ur);
            });
            userRoleRepository.saveAll(userRoles);
        }
        if(groups!=null){
            List<UserGroup> userGroups = new LinkedList<>();
            groups.forEach(g->{
                UserGroup ug = new UserGroup();
                ug.setGroupId(g);
                ug.setUserId(uid);
                userGroups.add(ug);
            });
            userGroupRepository.saveAll(userGroups);
        }
    }
}
